/*******************************************************************************
 * Copyright (c) 2006 CEA List.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     CEA List - initial API and implementation
 *******************************************************************************/
package com.cea.papyrus.core.dnd;

import java.util.Iterator;

import org.eclipse.gef.EditPartViewer;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.commands.CompoundCommand;
import org.eclipse.jface.util.TransferDropTargetListener;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.uml2.uml.Classifier;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Package;

import com.cea.papyrus.core.PapyrusPlugin;
import com.cea.papyrus.core.commands.UMLElementAddCommand;
import com.cea.papyrus.core.commands.factories.UMLDi2ElementDeleteFactory;
import com.cea.papyrus.core.editor.CommandStackUtils;
import com.cea.papyrus.core.helper.IGraphEdgeHelper;
import com.cea.papyrus.core.helper.IGraphElementHelper;
import com.cea.papyrus.core.helper.IModelerHelper;
import com.cea.papyrus.core.treeeditpart.CommonTreeEditPart;
import com.cea.papyrus.core.treeeditpart.DiagramTreeEditPart;
import com.cea.papyrus.core.treeeditpart.ElementTreeEditPart;
import com.cea.papyrus.core.treeeditpart.IGroupingTreeEditPart;

// TODO: Auto-generated Javadoc
/**
 * The Class TreeOutlinePageDropTargetListener.
 * 
 * @author Chokri Mraidha
 */
public class TreeOutlinePageDropTargetListener implements TransferDropTargetListener {
	
	/**
	 * The tree viewer.
	 */
	EditPartViewer treeViewer;
	
	/**
	 * The Constructor.
	 * 
	 * @param viewer the viewer
	 */
	public TreeOutlinePageDropTargetListener(EditPartViewer viewer){
		treeViewer = viewer;
	}
	
	/**
	 * Checks if is enabled.
	 * 
	 * @param event the event
	 * 
	 * @return true, if is enabled
	 */
	public boolean isEnabled(DropTargetEvent event) {
		if(treeViewer.getSelection().isEmpty())
			return false;
		return true;
	}
	
	/**
	 * Gets the transfer.
	 * 
	 * @return the transfer
	 */
	public Transfer getTransfer() {
		return ObjectTransfer.getInstance();
	}
	
	/**
	 * Drag enter.
	 * 
	 * @param event the event
	 */
	public void dragEnter(DropTargetEvent event){
	}

	/**
	 * Drag over.
	 * 
	 * @param event the event
	 */
	public void dragOver(DropTargetEvent event){
		// check item of the event is not null (Bug on scrollbars)
		if(event.item == null) {
			return;
		}
		
		// if the cursor is over a diagram do not allow drop
		if(event.item.getData() instanceof DiagramTreeEditPart) {
			event.detail = DND.DROP_NONE;
			return;
		} // the cursor is on a uml element
		else if(event.item.getData() instanceof ElementTreeEditPart) {
			Iterator<CommonTreeEditPart> iter = treeViewer.getSelectedEditParts().iterator();
			while(iter.hasNext()){
				CommonTreeEditPart currentElement = iter.next();
				if(currentElement instanceof ElementTreeEditPart) {
					Class elementClass = ((ElementTreeEditPart)currentElement).getUmlElement().getClass().getInterfaces()[0]; 
					IModelerHelper modelerFactory = PapyrusPlugin.getDefault().getFactoryRegistry().getFactory(elementClass);
					
					// fix bug for tree outline with imported elements (no move possible)
					if(modelerFactory==null) {
						event.detail = DND.DROP_NONE;
						return;
					}
					
					Object elementFactory = modelerFactory.getElementFactory(elementClass);
					
					// all uml elements but not an association
					if(elementFactory instanceof IGraphElementHelper){
						if(!((IGraphElementHelper)elementFactory).canCreateUMLElement(((ElementTreeEditPart)event.item.getData()).getUmlElement())){
							event.detail = DND.DROP_NONE;
							break;
						}
					}
					
					// association
					else if(elementFactory instanceof IGraphEdgeHelper){
							event.detail = DND.DROP_NONE;
							break;
					}
				}
				event.detail = DND.DROP_MOVE;
			}
		}

		// if the cursor is over a grouping edit part
		else if(event.item.getData() instanceof IGroupingTreeEditPart) {
			event.detail = DND.DROP_NONE;
			return;
		}

		//Defines the event feedback: auto-expand, select, auto-scroll, insert dragged item after the selected element
		event.feedback=DND.FEEDBACK_EXPAND|DND.FEEDBACK_SELECT|DND.FEEDBACK_SCROLL|DND.FEEDBACK_INSERT_AFTER;
	}

	/**
	 * Drag operation changed.
	 * 
	 * @param event the event
	 */
	public void dragOperationChanged(DropTargetEvent event){
	}

	/**
	 * Drag leave.
	 * 
	 * @param event the event
	 */
	public void dragLeave(DropTargetEvent event){
	}

	/**
	 * Drop accept.
	 * 
	 * @param event the event
	 */
	public void dropAccept(DropTargetEvent event){
	}

	/**
	 * Drop.
	 * 
	 * @param event the event
	 */
	public void drop(DropTargetEvent event){
		// check item is not null 
		// (removing Bug: NPE when dropping on scroll bars=> event.item is null
		if(event.item == null) {
			return;
		}
		
		// the target uml element
		Element target = ((ElementTreeEditPart)event.item.getData()).getUmlElement();
		
		// perform move
		if(event.detail==DND.DROP_MOVE){
			// the compound command to be executed
			CompoundCommand moveCommand = new CompoundCommand();

			if(getTransfer().isSupportedType(event.currentDataType)){
				Iterator<CommonTreeEditPart> iter = treeViewer.getSelectedEditParts().iterator();
				while(iter.hasNext()){
					CommonTreeEditPart currentEditPart = iter.next();

					// diagram case
					if(currentEditPart instanceof DiagramTreeEditPart){

					
					}

					// uml element case
					else if(currentEditPart instanceof ElementTreeEditPart){
						if( ((ElementTreeEditPart)currentEditPart).isElementImport()) {
							return;
						}
						UMLElementAddCommand addCommand = new UMLElementAddCommand(target, ((ElementTreeEditPart)currentEditPart).getUmlElement());

						if(! (((ElementTreeEditPart)currentEditPart).getUmlElement() instanceof Package) &&
								!(((ElementTreeEditPart)currentEditPart).getUmlElement() instanceof Classifier)) {
							Command deleteCommand = UMLDi2ElementDeleteFactory.eINSTANCE.createCommand(((ElementTreeEditPart)currentEditPart).getUmlElement());
							moveCommand.add(deleteCommand.chain(addCommand));
						}

						else
							moveCommand.add(addCommand);
					}
				}

				/** compound command execution **/
				if(CommandStackUtils.getCommandStack() !=null)
					CommandStackUtils.getCommandStack().execute(moveCommand);
			}	
		}
		
		
		// perform copy
		else if(event.detail==DND.DROP_COPY){
			
		}
	}
}
